﻿Imports System.Text
Imports System.Net

Namespace TwitterAPI
	Public Class TwitterService
		Public Event UsersCountChanged As EventHandler(Of UsersCountEventArgs)

		Private twitterClient As Client
        Private mHashCode As New HashCodeItem
        Private commands As New Dictionary(Of String, List(Of Action(Of IEnumerable(Of FeedItem))))()

        Public Sub Login(ByVal username As String, ByVal password As String)
            Me.twitterClient = New Client(username, password)
        End Sub

        Public Sub Login(ByVal credentials As ICredentials)
            Me.twitterClient = New Client(credentials)
        End Sub

        Public Property HashCode As String
            Get
                Return Me.mHashCode.HashCode
            End Get
            Set(ByVal value As String)
                mHashCode.HashCode = value
                Reset()
            End Set
        End Property

        Public Sub Reset()
            Me.mHashCode.Reset()
        End Sub

        Public Function GetUsersCount() As Integer
            Return Me.mHashCode.Users.Count()
        End Function

        Public Sub RegisterCommand(ByVal command As String, ByVal handler As Action(Of IEnumerable(Of FeedItem)))
            If Not commands.ContainsKey(command) Then
                commands.Add(command, New List(Of Action(Of IEnumerable(Of FeedItem)))())
            End If

            commands(command).Add(handler)
        End Sub

        Public Sub ProcessMessages(ByVal errorCallback As Action(Of Exception))
            Dim feeds = TwitterAPI.Client.GetTwitsByHashCode(mHashCode.HashCode, mHashCode.SinceId)
            If feeds.Count > 0 Then
                ProcessUsersCount(feeds)

                mHashCode.SinceId = feeds.Max(Of Long)(Function(feed) feed.Id)
                For Each command As String In Me.commands.Keys
                    Dim commandValue = command
                    Dim commandFeeds = feeds.Where(Function(feed) feed.Text.StartsWith(GetMessageWithHashcode(commandValue), StringComparison.OrdinalIgnoreCase))
                    Dim handler As Action(Of IEnumerable(Of FeedItem))

                    If commandFeeds.Count() > 0 Then
                        For Each handler In Me.commands(command)
                            Try
                                handler(commandFeeds)
                            Catch ex As Exception
                                errorCallback(ex)
                            End Try
                        Next handler
                    End If
                Next command
            End If
        End Sub

        Private Sub ProcessUsersCount(ByVal feeds As List(Of FeedItem))
            Dim oldUsersCount = Me.GetUsersCount()
            feeds.Select(Function(feed) feed.User).Distinct().ToList().ForEach(Sub(user) mHashCode.AddUser(user))
            Dim newUsersCount = Me.GetUsersCount()

            If oldUsersCount <> newUsersCount Then
                OnUsersCountChanged(New UsersCountEventArgs(oldUsersCount, newUsersCount))
            End If
        End Sub

		Protected Overridable Sub OnUsersCountChanged(ByVal e As UsersCountEventArgs)
			RaiseEvent UsersCountChanged(Me, e)
		End Sub

		Public Function GetMessageWithHashcode(ByVal message As String) As String
            Dim result = HashCode & " " & message

            If Not result.StartsWith("#") Then
                result = "#" & result
            End If

			Return result
		End Function

		Public Function GetMessagesWithHashcode(ByVal message As String) As List(Of String)
            Dim messages As New List(Of String)
            Dim tempHashCode = (If(HashCode.StartsWith("#"), "", "#")) & HashCode & " "
            Dim twitterSizeWithHashCode = 140 - tempHashCode.Length

			Do While message.Length > 0
                Dim cropPosition = Math.Min(message.Length, twitterSizeWithHashCode)
				messages.Add(tempHashCode & message.Substring(0, cropPosition))
				message = message.Substring(cropPosition)
			Loop

			Return messages
		End Function

		Public Sub UpdateStatus(ByVal message As String)
			Me.twitterClient.UpdateStatus(message)
		End Sub

		Public Sub UpdateStatus(ByVal messages As List(Of String))
            messages.Reverse()
            messages.ToList().ForEach(Sub(message) Me.twitterClient.UpdateStatus(message))
		End Sub

		Private Class HashCodeItem
            Private mUsers As New List(Of String)

            Public Property HashCode As String
            Public Property SinceId As Long

            Public ReadOnly Property Users As IEnumerable(Of String)
                Get
                    Return Me.mUsers
                End Get
            End Property

            Public Sub AddUser(ByVal user As String)
                If Not mUsers.Contains(user) Then
                    Me.mUsers.Add(user)
                End If
            End Sub

            Public Sub Reset()
                Me.SinceId = 0
                Me.mUsers = New List(Of String)
            End Sub
		End Class
	End Class
End Namespace
